///////////////////////////////////YUNYOO.CN//////////////////////////////////////
//                                                                               *
// This file is part of A64Dbg and VMPStudio gui frontend project.               *
//                                                                               *
// Copyright(C) 2021 YunYoo Corp., ALL RIGHTS RESERVED.                          *
//                                                                               *
// Internet: yunyoo.cn                                                           *
//                                                                               *
// This code is distributed "as is", part of YUNYOO.CN and without warranty of   *
// any kind, expressed or implied, including, but not limited to warranty of     *
// fitness for any particular purpose. In no event will YUNYOO.CN be liable to   *
// you for any special, incidental, indirect, consequential or any other         *
// damages caused by the use, misuse, or the inability to use of this code,      *
// including anylost profits or lost savings, even if YUNYOO.CN has been advised *
// of the possibility of such damages.                                           *
//                                                                               *
///////////////////////////////////////*//////////////////////////////////////////


#pragma once

#include <functional>

#include <abstraction/Disassembler.h>
#include <abstraction/LLDBEngine.hpp>
#include <abstraction/MagicAna.hpp>

namespace dbgapi {

// some extra utils

std::string __MANA_API__ tburl_request(const char *ip, const char *command,
                                       const char *body);
std::string __MANA_API__ tburl_request(const char *ip, const char *command,
                                       const char *param, const char *body);
bool __MANA_API__ tbget_file_ex(const char *ip, const char *path,
                                const char *savepath);

bool __MANA_API__ is_android_64(const char *adb, int pid, const char *exe);

void __MANA_API__ adb_pull(const char *adb, const char *rfile,
                           const char *locfile);
std::string __MANA_API__ adb_push(const char *adb, const char *file);
std::string __MANA_API__ adb_shell(const char *adb, const char *cmd, bool root);

// uvmdbg command type

enum UVMDBG_CommandType {
  udct_disconnect,

  udct_s2c_init,
  udct_s2c_modules,
  udct_s2c_threads,
  udct_s2c_callstack,
  udct_s2c_readmem,
  udct_s2c_writemem,
  udct_s2c_setbp,
  udct_s2c_run,
  udct_s2c_pause,
  udct_s2c_stepinto,
  udct_s2c_stepover,
  udct_s2c_stepout,
  udct_s2c_stepbbend,
  udct_s2c_updatectx,
  udct_s2c_switchthread,
  udct_s2c_runadc,

  udct_c2s_ready,
  udct_c2s_modules,
  udct_c2s_bpsetted,
  udct_c2s_stopped,
  udct_c2s_bphited,
  udct_c2s_memory,
  udct_c2s_threads,
  udct_c2s_callstack,
  udct_c2s_switchthread,
  udct_c2s_log,
  udct_c2s_adcoutput,
};

// uraniumvm server command type

enum UVMSVR_CommandType {
  uvmct_s2c_init,
  uvmct_s2c_shell_result,
  uvmct_s2c_getfile_result,
  uvmct_s2c_postfile_result,

  uvmct_c2s_shell,
  uvmct_c2s_shell_timeout,
  uvmct_c2s_getfile,
  uvmct_c2s_postfile,
};

// UraniumVM trace server running inside VMPStudio
class __MANA_API__ UraniumVMServer {
 public:
  UraniumVMServer();
  ~UraniumVMServer();

  void start(
      std::function<void()> income,
      std::function<void(UVMDBG_CommandType, const char *, int, uint64_t)>
          protocol);
  void stop();
  int send(UVMDBG_CommandType type, const char *buf = nullptr,
           size_t bufsz = 0, uint64_t extra = 0);
  void disconnect();

  static const char *local_ip();

 protected:
  void *m_ctx;
};

#if __arm64__
// UVM helper server running inside M1 macOS's VMPStudio
class __MANA_API__ UVMServer {
 public:
  UVMServer();
  ~UVMServer();

  static void start();
  static void stop();
};
#endif

// client of UVMServer
class __MANA_API__ UVMClient {
 public:
  UVMClient();
  ~UVMClient();

  void connect(
      const char *remoteip,
      std::function<void(UVMSVR_CommandType, const char *, int, uint64_t)>
          protocol);
  void close();
  int send(UVMSVR_CommandType type, const char *buf, size_t bufsz,
           uint64_t extra = 0);
  bool valid();

 protected:
  void *m_ctx;
};

// sub regs

#pragma pack(push)
#pragma pack(1)

struct arm_subregs_t {
  uint32_t flags;
  uint32_t gprs[14];
};

struct arm64_subregs_t {
  uint32_t flags;
  uint64_t gprs[31];
};

struct arm_pcreg_record_header_t {
  uint64_t pc;
  uint32_t count;
  arm_subregs_t subregs[0];
};

struct arm64_pcreg_record_header_t {
  uint64_t pc;
  uint32_t count;
  arm64_subregs_t subregs[0];
};

#pragma pack(pop)  // end of byte align

} // end of dbgapi
